package com.tanguy.user.utlis.extend

import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.provider.Settings
import android.text.Spannable
import android.text.SpannableString
import android.util.Log
import cn.sinata.xldutils_kotlin.data.ResultData
import cn.sinata.xldutils_kotlin.rxutils.Error
import cn.sinata.xldutils_kotlin.rxutils.ResultException
import com.google.gson.JsonSyntaxException
import com.tanguy.user.App
import com.tanguy.user.App.Companion.app
import com.tanguy.user.Const
import com.tanguy.user.R
import com.tanguy.user.bean.User
import com.tanguy.user.custom.CenterImageSpan
import com.tanguy.user.interfaces.RequestHelper
import com.tanguy.user.net.http.HttpManager
import com.tanguy.user.ui.me.activity.account.SetPasswordActivity
import com.tanguy.user.ui.window.LoginWindow
import com.tanguy.user.ui.window.MessageWindow
import com.tanguy.user.utlis.StackManager
import com.tanguy.user.utlis.TimeUtils
import com.weigan.loopview.LoopView
import io.reactivex.Observable
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import org.jetbrains.anko.startActivity
import retrofit2.HttpException
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.util.*
import java.util.concurrent.TimeUnit

/**
 * Created by dab on 2017/11/2 0002 14:06
 * 一些公共方法
 */
/**
 * 打印日志,快速定位到日志的位置,会收集栈的信息
 */
fun loge(msg: Any? = null, stack: Int = 2, myTag: String = "tanguy_loge") {
    if (!Const.DEBUG.All) return
    val stackTrace = Throwable().stackTrace
    val className = stackTrace[stack].fileName
    val methodName = stackTrace[stack].methodName
    val lineNumber = stackTrace[stack].lineNumber
    val tag = "($className:$lineNumber)"
    val msg = ("$myTag $methodName:${msg.toString()}")
    Log.e(tag, msg)
}

/**
 * 倒计时s
 */
inline fun countDownTimer(millisUntilFinish: Long, crossinline block: (finish: Boolean, millisUntilFinished: Long) -> Unit): Disposable {
    var subscribe: Disposable? = null
    subscribe = Observable.interval(0, 1000, TimeUnit.MILLISECONDS)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe {
                if (it < millisUntilFinish) {
                    block.invoke(false, millisUntilFinish - it)
                } else {
                    block.invoke(true, 0)
                    if (subscribe != null && !subscribe!!.isDisposed) {
                        subscribe?.dispose()
                    }
                }
            }
    return subscribe
}

/**
 * 验证码的倒计时
 */
inline fun captchaCountDownTimer(crossinline block: (finish: Boolean, msg: String) -> Unit): Disposable {
    return countDownTimer(60) { finish, millisUntilFinished ->
        if (finish) {
            block.invoke(finish, "重新获取验证码")
        } else {
            block.invoke(finish, "${millisUntilFinished}s")

        }

    }
}

/**
 * 获取带箭头的标题
 */
fun Context.getTitleText(title: String): SpannableString {
    val imgSpan = CenterImageSpan(this, R.mipmap.title_xialajiantou)
    val spanString = SpannableString("${title}icon")
    spanString.setSpan(imgSpan, title.length, title.length + 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
    return spanString
}


/**
 * 计时器(注意不需要的时候要取消订阅)
 */
inline fun rxTimer(interval: Long, crossinline block: (times: Long) -> Unit): Disposable {
    var subscribe: Disposable? = null
    subscribe = Observable.interval(0, interval, TimeUnit.MILLISECONDS)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe {
                block.invoke(it)
            }
    return subscribe
}

/**
 * 是否包含表情
 */
fun containsEmoji(str: String): Boolean {//真为不含有表情
    val len = str.length
    for (i in 0 until len) {
        if (isEmojiCharacter(str[i])) {
            return true
        }
    }
    return false
}

private fun isEmojiCharacter(codePoint: Char): Boolean {
    return !(codePoint.toInt() == 0x0 ||
            codePoint.toInt() == 0x9 ||
            codePoint.toInt() == 0xA ||
            codePoint.toInt() == 0xD ||
            codePoint.toInt() in 0x20..0xD7FF ||
            codePoint.toInt() in 0xE000..0xFFFD ||
            codePoint.toInt() in 0x10000..0x10FFFF)
}

/**
 * 获取设备id
 */
@SuppressLint("HardwareIds")
fun Context.getDeviceId(): String = Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID)

/**
 * 修改屏幕的透明度
 */
fun changeWindowAlpha(activity: Activity?, alpha: Float) {
    if (activity == null) {
        loge("changeWindowAlpha: window == null")
        return
    }

    val lp = activity.window.attributes
    lp.alpha = alpha
    activity.window.attributes = lp

}

inline fun Activity.login(crossinline login: (user: User?) -> Unit) {
    val window = LoginWindow(this) { user, loginType ->
        if (loginType == -1) {
            //表示取消了登录
            login.invoke(null)
            return@LoginWindow
        }
        //  1=表示跳转到设置密码 没有设置密码 2=已经设置了密码 直接跳转我的
        if (user?.type == 1) {
            this.startActivity<SetPasswordActivity>()
        } else {
            //登录成功
            login.invoke(user)
        }
    }
    showPopupWindow(window)
    window.setOnDismissListener {
        changeWindowAlpha(this, 1f)
    }
    changeWindowAlpha(this, 0.7f)
}

/**
 * 隐藏车牌号（需要用到java的String类）
 */
fun hindCarNumber(carNumber: String): String {
    val string = carNumber as java.lang.String
    return string.replaceAll("(\\d{0})\\d{3}(\\d{1})", "$1***$2")
}

/**
 * 保证登录(user==null 表示登录取消了)
 */
inline fun Activity.loginGuarantee(crossinline login: (user: User?) -> Unit) {
    if (App.app.isLogin) {
        login.invoke(app.user)
        return
    }
    val loginWindow = LoginWindow(this) { user, loginType ->
        if (loginType == -1) {
            //表示取消了登录
            login.invoke(null)
            return@LoginWindow
        }
        //  1=表示跳转到设置密码 没有设置密码 2=已经设置了密码 直接跳转我的
        if (user?.type == 1) {
            this.startActivity<SetPasswordActivity>()
        } else {
            //登录成功
            login.invoke(user)
        }
    }

    showPopupWindow(loginWindow)
    loginWindow.setOnDismissListener {
        changeWindowAlpha(this, 1f)
    }
    changeWindowAlpha(this, 0.7f)
}

/**
 * 通过反射拿到LoopView控件当前选择的数据
 *
 * @param loopView
 * @return
 */
fun LoopView.getSelectedItemString(): String? {
    val aClass = this.javaClass
    val declaredFields = aClass.declaredFields
    for (field in declaredFields) {
        if (field.name == "items") {
            try {
                field.isAccessible = true
                val list = field.get(this) as List<String>
                return list[this.selectedItem]
            } catch (e: Exception) {
                e.printStackTrace()
            }

        }
    }
    return null
}

fun getTimeDDMM(time: Long, nowTime: Long = System.currentTimeMillis()): String {
    fun getStartTimeOfDay(now: Long): Long {
        val tz = "GMT+8"
        val curTimeZone = TimeZone.getTimeZone(tz)
        val calendar = Calendar.getInstance(curTimeZone)
        calendar.timeInMillis = now
        calendar.set(Calendar.HOUR_OF_DAY, 0)
        calendar.set(Calendar.MINUTE, 0)
        calendar.set(Calendar.SECOND, 0)
        calendar.set(Calendar.MILLISECOND, 0)
        return calendar.timeInMillis
    }

    var desc = ""
    val startTimeOfDay = getStartTimeOfDay(nowTime)
    val l = time - startTimeOfDay
    val data = l / 1000 / 24 / 60 / 60
    when (data.toInt()) {
        -1 -> desc = "前天"
        0 -> desc = if (l > 0) "今天" else "昨天"
        1 -> desc = "明天"
        2 -> desc = "后天"
    }
    if (desc == "今天" || desc == "明天") {
        desc += time.toTimeString(TimeUtils.TIME_MM_DD_HH_MM)
    } else {
        desc = time.toTimeString(TimeUtils.TIME_YYYY_MM_DD_HH_MM_01)
    }
    return desc
}

/**
 * 取消订单，成功后会回调，失败就不会回调
 */
fun cancelOrder(id: String, ok: () -> Unit) {
    val currentActivity = StackManager.currentActivity()
    HttpManager.trvalcenlOrder(id)
            .requestSucceed(currentActivity as RequestHelper) {
                val type = it.get("type").asInt
                if (type == 1) {
                    currentActivity.showToast("取消成功")
                    ok.invoke()
                    return@requestSucceed
                } else {
                    val kou = it.get("kou").asDouble
                    val msg = "此时取消订单将扣除￥${kou}作为司机的补偿,您确定要取消订单?"
                    currentActivity.showPopupWindow(MessageWindow(currentActivity, msg) {
                        if (it) {
                            //todo 未给出原因图,原因是选的
                            HttpManager.trvalcenltow(id, kou.toString(),"未给出原因图")
                                    .requestSucceed(currentActivity) {
                                        currentActivity.showToast("取消成功")
                                        ok.invoke()
                                    }
                        }
                    })
                }
            }
}


/**
 * 简化请求的一个方法(只有code==0时才算成功),直接在主线程返回,如果请求失败,会在这个里面提醒用户
 * 请求需要一个RequestHelper接口,因为要
 *     显示请求动画,
 *     取消动画,
 *     请求完成自动取消订阅,
 *     取消未完成时取消请求,
 *     错误提醒的弹窗提示
 *
 * 在调试的时候没有使用inline,因为内联会把回调内联进函数,日志不好记录堆栈的信息
 *
 */
fun <O, I : ResultData<O>> Observable<I>.requestSucceed(requestHelper: RequestHelper, showLoadDialog: Boolean = true, data: (data: O) -> Unit) {
    this.request(requestHelper, showLoadDialog) {
        if (it == null) return@request
        if (it.code == 0) {
            data.invoke(it.data as O)
        } else {
            requestHelper.showToast(it.msg)
        }
    }
}

/**
 * 返回所有的请求成功的数据,code!=0时也会返回
 * 如果需要code不为0时,不直接提示,而是需要处理的时候,使用这个
 */
fun <T> Observable<T>.request(requestHelper: RequestHelper, showLoadDialog: Boolean = true, data: (t: T?) -> Unit) {
    this
            .subscribeOn(Schedulers.io())
            .doOnSubscribe {
                if (showLoadDialog)
                    requestHelper.showLoadDialog()
            }
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : Observer<T> {
                var disposable: Disposable? = null
                override fun onError(t: Throwable) {
                    requestHelper.dismissLoadDialog()
                    var msg = t.message
                    var code = -1
                    when (t) {
                        is JsonSyntaxException -> msg = Error.PARSER_ERROR
                        is ConnectException -> msg = Error.NET_ERROR
                        is SocketTimeoutException -> msg = Error.NET_ERROR
                        is HttpException -> msg = Error.SERVER_ERROR
                        is ResultException -> {
                            code = t.code
                            msg = t.message!!
                        }
                    }
                    data.invoke(null)
                    requestHelper.showToast(msg)
                    if (Const.DEBUG.RESPONSE)
                        t.printStackTrace()
                }

                override fun onSubscribe(d: Disposable) {
                    disposable = d
                    requestHelper.cancelRequest(d)
                }

                override fun onComplete() {
                    requestHelper.dismissLoadDialog()
                    if (disposable != null && !disposable!!.isDisposed) {
                        disposable?.dispose()
                    }
                }

                override fun onNext(t: T) {
                    requestHelper.dismissLoadDialog()
                    data.invoke(t)
                }

            })
}